package mac10.util;

import java.util.ArrayList;

import mac10.models.Cell;
import mac10.models.Point;
import mac10.models.WorldModel;

public class AStarHeapShepherd extends AStarHeap
{

//    private WorldModel world;
//    private Node start, goal;
//    private OpenHeap openlist;
//    private boolean avoidClosedFences, avoidOpenFences, avoidCows, avoidAgents;
//    private int[][] nodeStates;
    private int[][] weights;
//    private int lineOfAvoiding;

//    private static final int OPEN = 1;
//    private static final int CLOSED = 2;

    public AStarHeapShepherd (WorldModel world, Point start, Point goal,
            ArrayList<? extends Point> cluster)
    {
    	super(world, start, goal);
    	
//        this.world = world;
//        int fstart = 0 + start.maxNorm(goal);
//        this.start = new Node(start, 0, fstart);
//        this.goal = new Node(goal, Integer.MAX_VALUE, Integer.MAX_VALUE);
//        this.openlist = new OpenHeap();
        int sizex = world.getWidth();
        int sizey = world.getHeight();
//        this.nodeStates = new int[sizex][sizey];
//        this.lineOfAvoiding = 5;
        this.weights = new int[sizex][sizey];
//        for (int x = 0; x < sizex; x++)
//        {
//            for (int y = 0; y < sizey; y++)
//            {
//                weights[x][y] = 1;
//            }
//        }
        final int r = 3;
        for (Point cow : cluster)
        {

        	// this part is very similar to what is done in WorldModel.updateModel()
        	
            int x = cow.getX();
            int y = cow.getY();
            for (int i = -r; i <= r && x + i >= 0 && x + i < sizex; i++)
            {
                for (int j = -r; j <= r && y + j >= 0 && y + j < sizey; j++)
                {
                    int distance = Math.max(Math.abs(i), Math.abs(j));
                    weights[x + i][y + j] += r - distance;
                }
            }
        }
    }

    /**
     * Calculates the path from start to goal If path was found, the path can be
     * reconstructed recursively with the predecessor of the goal-node
     * 
     * @return goal-node or null if no path was found
     */
//    public Node AStar (long deadline)
//    {
//        openlist = new OpenHeap();
//        nodeStates = new int[world.getWidth()][world.getHeight()];
//        openlist.add(start);
//
//        while (!openlist.isEmpty())
//        {
//            long time = System.currentTimeMillis();
//            if (time > deadline - 20)
//                return null;
//            Node curr = openlist.poll();
//            // System.out.println(curr);
//            if (curr.equals(goal))
//            {
//                return curr;
//            }
//            expandNode(curr);
//
//            nodeStates[curr.getX()][curr.getY()] = CLOSED;
//        }
//        return null;
//    }

//    protected void expandNode (Node curr)
//    {
//        ArrayList<Cell> cells = this.world.getNeighbours(curr.getX(), curr
//                .getY());
//        for (Cell cell : cells)
//        {
//            if (nodeStates[cell.getX()][cell.getY()] == CLOSED)
//                continue;
//            // these cells are never accessible
//            if (cell.isObstacle() || cell.isSwitch())
//                continue;
//
//            if (cell.maxNorm(start) < lineOfAvoiding)
//            {
//                if (avoidClosedFences && cell.isFence() && !cell.isOpen())
//                    continue;
//                if (avoidOpenFences && cell.isFence() && cell.isOpen())
//                    continue;
//                if (avoidCows && cell.isCow())
//                    continue;
//                if (avoidAgents && (cell.isAllyAgent() || cell.isEnemyAgent()))
//                    continue;
//            }
//
//            int fsucc = calcFSucc(curr, cell);
//
//            Node successor = new Node(cell, curr.getG() + 1, fsucc, curr);
//            // System.out.println("\t"+successor+" f: "+fsucc);
//
//            if (nodeStates[cell.getX()][cell.getY()] == OPEN)
//            {
//                openlist.updateNode(successor);
//            }
//            else
//            {
//                nodeStates[cell.getX()][cell.getY()] = OPEN;
//                openlist.add(successor);
//            }
//        }
//    }
//    
	@Override
	protected int calcFSucc(Node curr, Cell cell) {
		return curr.getG() + weights[cell.getX()][cell.getY()]
				+ goal.maxNorm(cell);
	}

//    /**
//     * @return the avoidOpenFences
//     */
//    public boolean isAvoidOpenFences ()
//    {
//        return avoidOpenFences;
//    }
//
//    /**
//     * @param avoidOpenFences
//     *            the avoidFences to set
//     */
//    public void setAvoidOpenFences (boolean avoidOpenFences)
//    {
//        this.avoidOpenFences = avoidOpenFences;
//    }
//
//    /**
//     * @return the avoidClosedFences
//     */
//    public boolean isAvoidClosedFences ()
//    {
//        return avoidClosedFences;
//    }
//
//    /**
//     * @param avoidOpenFences
//     *            the avoidFences to set
//     */
//    public void setAvoidClosedFences (boolean avoidClosedFences)
//    {
//        this.avoidClosedFences = avoidClosedFences;
//    }
//
//    /**
//     * @return the avoidCows
//     */
//    public boolean isAvoidCows ()
//    {
//        return avoidCows;
//    }
//
//    /**
//     * @param avoidCows
//     *            the avoidCows to set
//     */
//    public void setAvoidCows (boolean avoidCows)
//    {
//        this.avoidCows = avoidCows;
//    }
//
//    /**
//     * @return the avoidAgents
//     */
//    public boolean isAvoidAgents ()
//    {
//        return avoidAgents;
//    }
//
//    /**
//     * @param avoidAgents
//     *            the avoidAgents to set
//     */
//    public void setAvoidAgents (boolean avoidAgents)
//    {
//        this.avoidAgents = avoidAgents;
//    }
//
//    /**
//     * @return the lineOfAvoiding
//     */
//    public int getLineOfAvoiding ()
//    {
//        return lineOfAvoiding;
//    }
//
//    /**
//     * @param lineOfAvoiding
//     *            the lineOfAvoiding to set
//     */
//    public void setLineOfAvoiding (int lineOfAvoiding)
//    {
//        this.lineOfAvoiding = lineOfAvoiding;
//    }
}
